package czolgisci.display;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.*;

import czolgisci.Engine;

/**
 * Okno gry. Inicjalizuje główną klasę gry Engine.
 * 
 * @author pillow
 * @pattern Singleton
 * @version 0.3
 */
public class GraphicInterface extends JFrame implements ActionListener
{
	private static GraphicInterface instance = null;

	private static final long serialVersionUID = 1L;
	private JPanel upper;
	private ImagePanel bottom;
	private JTextField playerFields[];
	private JLabel playerLabels[];
	private Map<String, JLabel> livesFields;
	private int playersNumber;

	/**
	 * Prywatny konstruktor klasy
	 * @see getInstance()
	 */
	private GraphicInterface()
	{
	}
	
	/**
	 * Metoda wzorca Singleton
	 * 
	 * @return jedyna instancja klasy
	 */
	static public GraphicInterface getInstance()
	{
		if (instance == null)
		{
			instance = new GraphicInterface();
		}
		return instance;
	}
	
	/**
	 * Inicjuje interfejs graficzny
	 * @param title tytuł okna
	 * @param playersNumber liczba graczy
	 * @throws IllegalArgumentException
	 */
	public void init(String title, int playersNumber) throws IllegalArgumentException
	{
		if (playersNumber < 2)
			throw new IllegalArgumentException("too small number of players (min 2)");

		this.playersNumber = playersNumber;
		playerFields = new JTextField[this.playersNumber];
		livesFields = new HashMap<String, JLabel>();

		setTitle(title);
		setMinimumSize(new Dimension(490, 390));
		setResizable(false);
		setDefaultCloseOperation(GraphicInterface.EXIT_ON_CLOSE);
		setLocation(100, 100);
		upper = new JPanel(new FlowLayout());
		upper.setBorder(BorderFactory.createEmptyBorder());
		upper.setBackground(Color.LIGHT_GRAY);

		bottom = new ImagePanel();
		bottom.setBorder(BorderFactory.createEmptyBorder());

		drawSplash();
	}

	/**
	 * tworzy pole żyć dla danego gracza
	 * 
	 * @param playerName imię gracza
	 * @param lifes ilość żyć
	 */
	public void createLifeField(String playerName, int lifes) throws IllegalArgumentException
	{
		if (lifes <= 0)
			throw new IllegalArgumentException("too small lifes number (must be greater than zero");

		JLabel newField = new JLabel(playerName + "[" + lifes + "]");
		livesFields.put(playerName, newField);

		upper.setLayout(new FlowLayout());
		upper.add(newField);
		setVisible(true);
	}

	/**
	 * aktualizuje pole żyć danego gracza
	 * 
	 * @param playerName imię gracza
	 * @param lifes ilość żyć
	 */
	public void updateLifeField(String playerName, int lifes)
	{
		if (lifes < 0)
			throw new IllegalArgumentException("too small lifes number (must be min 0");

		JLabel field = livesFields.get(playerName);
		field.setText(playerName + "[" + lifes + "]");
		livesFields.put(playerName, field);
		pack();
		setVisible(true);
	}

	/**
	 * wyswietla splash informujacy o zakończeniu gry, wskazuje zwycięzce
	 * 
	 * @param winnerName imię zwycięzcy
	 */
	public void endGame(String winnerName)
	{
		upper.removeAll();
		if (winnerName != null)
			upper.add(new JLabel("Wygrał: " + winnerName));
		else
			upper.add(new JLabel("Remis"));

		JButton restartButton = new JButton("Restart?");
		restartButton.setActionCommand("Restart game");
		restartButton.addActionListener(this);

		upper.add(restartButton);
		setVisible(true);
	}

	/**
	 * Wyświetla splash początkowy z prośbą o podanie imion graczy
	 */
	private void drawSplash()
	{
		playerLabels = new JLabel[playersNumber];
		playerFields = new JTextField[playersNumber];

        playerLabels[0] = new JLabel("Gracz 1:");
        playerFields[0] = new JTextField();

        playerLabels[1] = new JLabel("Gracz 2:");
        playerFields[1] = new JTextField();

        JButton okButton = new JButton("Go!");

        GroupLayout upperLayout = new GroupLayout(upper);
        upper.setLayout(upperLayout);
        upperLayout.setHorizontalGroup(
            upperLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(upperLayout.createSequentialGroup()
                .addGap(38, 38, 38)
                .addComponent(playerLabels[0])
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(playerFields[0], GroupLayout.PREFERRED_SIZE, 74, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(playerLabels[1])
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(playerFields[1], GroupLayout.PREFERRED_SIZE, 62, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(okButton)
                .addContainerGap(40, Short.MAX_VALUE))
        );
        upperLayout.setVerticalGroup(
            upperLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(GroupLayout.Alignment.TRAILING, upperLayout.createSequentialGroup()
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(upperLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(playerLabels[0])
                    .addComponent(playerLabels[1])
                    .addComponent(okButton)
                    .addComponent(playerFields[0], GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(playerFields[1], GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
        );

        GroupLayout bottomLayout = new GroupLayout(bottom);
        bottom.setLayout(bottomLayout);
        bottomLayout.setHorizontalGroup(
            bottomLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGap(0, 407, Short.MAX_VALUE)
        );
        bottomLayout.setVerticalGroup(
            bottomLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGap(0, 307, Short.MAX_VALUE)
        );

        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addComponent(upper, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(bottom, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(upper, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bottom, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        
		try
		{
			BufferedImage splashImage = (BufferedImage) ImageIO.read(new File("res/img/splashImage.jpg"));
			bottom.setImage(splashImage);
			
		} catch (IOException e)
		{
			e.printStackTrace();
		}

        pack();

		okButton.setActionCommand("Player names entered");
		okButton.addActionListener(this);
		setVisible(true);
	}

	/**
	 * Inicjalizuje główną klasę gry Engine
	 */
	private void initGame()
	{
		String players[] = new String[playersNumber];
		int i = 0;

		for (JTextField name : playerFields)
		{
			players[i] = name.getText();
			i++;
		}

		Engine.getInstance().init(this, bottom, players);
	}

	/**
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e)
	{
		if ("Player names entered".equals(e.getActionCommand()))
		{
			if (playerFields[0].getText().equals(playerFields[1].getText()))
			{
				return;
			}

			// wylaczenie splasha
			upper.removeAll();
			upper.repaint();
			// zainicjowanie gry
			requestFocus();
			initGame();
		}
		else if ("Restart game".equals(e.getActionCommand()))
		{
			upper.removeAll();
			upper.repaint();
			requestFocus();
			initGame();
		}
		
	}
}
